package per.poker.chouwangba;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import javafx.application.Platform;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.*;
import javafx.scene.effect.DropShadow;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.FlowPane;
import javafx.scene.paint.Color;
import javafx.stage.StageStyle;
import javafx.util.Pair;
import lombok.extern.slf4j.Slf4j;
import per.poker.common.CommonService;

import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.LockSupport;

/**
 * @author ：yunjia
 * @date ：2023/11/10 13:40
 * @description：
 * @modified By：
 * @version: 1.0
 */
@Slf4j
class ChouwangbaService extends ChouwangbaData {

    private Game game;
    private Thread thread = null;
    private final int waitTime = 100;

    public void discard() throws InterruptedException {
        //各自把对子丢弃
        for (Player player : game.getPlayerList()) {

            Set<String> discardList = new HashSet<>();

            List<String> cards = player.getCards();
            for (int i = 0; i < cards.size(); i++) {

                for (int j = i + 1; j < cards.size(); j++) {

                    boolean flag = isMatched(cards.get(i), cards.get(j));
                    if (flag) {
                        discardList.add(cards.get(i));
                        discardList.add(cards.get(j));
                    }
                }
            }

            if (!discardList.isEmpty()) {
                log.info("{} 丢弃扑克牌 {}", player.getName(), discardList);

                Label label = new Label();
                label.setPrefWidth(670);
                label.setPrefHeight(36);
                label.setText(StrUtil.format("————————玩家 {}  弃牌————————", player.getName()));
                label.setAlignment(Pos.CENTER);

                FlowPane flowPane = new FlowPane();
                flowPane.setPrefWidth(670);
                flowPane.setPrefHeight(114);

                for (String s : discardList) {
                    ImageView imageView = new ImageView();
                    imageView.setId(s);
                    imageView.setFitWidth(53);
                    imageView.setFitHeight(75);
                    imageView.setPreserveRatio(true);
                    imageView.setPickOnBounds(true);

                    imageView.setImage(new Image(CommonService.getPicUrl("/img/" + s + ".jpg")));
                    flowPane.getChildren().add(imageView);

                    Platform.runLater(() -> destroyCard(player.getName(), s));
                }

                Platform.runLater(() -> {
                    stage.getChildren().add(label);
                    stage.getChildren().add(flowPane);

                });

                cards.removeAll(discardList);
                if (cards.isEmpty()) {
                    player.setFinished(true);
                }
                Thread.sleep(waitTime);
                scrollPane.vvalueProperty().setValue(1.0);

            }

        }

    }

    public void startGame() throws InterruptedException {
        discard();

        Player startPlayer = game.getPlayerList().stream()
                .min(Comparator.comparingInt(p -> p.getCards().size()))
                .orElse(null);
        if (startPlayer == null) {
            throw new RuntimeException();
        }
        startPlayer.setReady(true);

        AtomicInteger idx = new AtomicInteger(0);
        for (Player player : game.getPlayerList()) {
            if (ObjectUtil.equal(player.getName(), startPlayer.getName())) {
                break;
            }
            idx.incrementAndGet();
        }
        //调试
        /*Player startPlayer = game.getPlayerList().get(2);
        AtomicInteger idx = new AtomicInteger(2);
        startPlayer.setReady(true);*/

        while (game.getIsStarted()) {
            startPlayer = game.getPlayerList().get(idx.get() % 4);
            if (startPlayer.getFinished()) {
                idx.incrementAndGet();
                continue;
            }
            Thread.sleep(waitTime);
            log.info(StrUtil.format("————————轮到玩家 {}————————", startPlayer.getName()));

            end(startPlayer);

            print();
            Label label = new Label();
            label.setPrefWidth(670);
            label.setPrefHeight(36);
            label.setText(StrUtil.format("————————轮到玩家 {}————————", startPlayer.getName()));
            label.setAlignment(Pos.CENTER);
            Platform.runLater(() -> {
                stage.getChildren().add(label);
                scrollPane.vvalueProperty().setValue(1.0);
            });

            //找到下家抽牌
            Player p;
            do {
                List<Player> playerList = game.getPlayerList();
                int index = (idx.get() + 1) % 4;
                p = playerList.get(index);
                idx.incrementAndGet();
            } while (p.getFinished());

            //自己抽下家
            if ("south".equals(startPlayer.getName())) {
                confirm.setDisable(false);

                for (Node child : getByName(p.getName()).getChildren()) {
                    Player finalP = p;
                    child.setOnMouseClicked(e -> {

                        if (child.getEffect() == null) {
                            child.setEffect(new DropShadow(15, Color.LIGHTSKYBLUE));
                        } else {
                            child.setEffect(null);
                        }

                        for (Node c : getByName(finalP.getName()).getChildren()) {
                            if (ObjectUtil.notEqual(c.getId(), child.getId())) {
                                c.setEffect(null);
                            }
                        }
                    });
                }

                thread = Thread.currentThread();
                LockSupport.park();
            }
            //下家是自己
            else if ("south".equals(p.getName())) {
                confirm.setDisable(true);

                int ran = RandomUtil.randomInt(0, p.getCards().size());
                String card = p.getCards().get(ran);

                south.lookup("#" + card).setEffect(new DropShadow(15, Color.valueOf("#00ffe4")));

                Thread.sleep(waitTime);
                Player finalStartPlayer = startPlayer;

                log.info("{} 得到 {}", startPlayer.getName(), card);

                Object o = new Object();
                Platform.runLater(() -> {
                    destroyCard("south", card);
                    addCard(finalStartPlayer.getName(), card);

                    try {
                        Thread.sleep(waitTime);
                        discard();
                        synchronized (o) {
                            o.notify();
                        }

                    } catch (InterruptedException ex) {
                        throw new RuntimeException(ex);
                    }
                });

                synchronized (o) {
                    o.wait();
                }

            }
            //电脑抽电脑
            else {
                confirm.setDisable(true);

                int nextRan = RandomUtil.randomInt(0, p.getCards().size());
                String toPresentCard = p.getCards().get(nextRan);

                //西
                if ("west".equals(startPlayer.getName())) {

                    ImageView toWest = (ImageView) getByName(p.getName()).lookup("#" + toPresentCard);

                    toWest.setEffect(new DropShadow(15, Color.valueOf("#00ffe4")));
                    Thread.sleep(waitTime);

                    String westId = toWest.getId();

                    log.info("west 得到 {}", westId);
                    toWest.setEffect(null);

                    Object o = new Object();
                    Player finalP1 = p;
                    Platform.runLater(() -> {
                        destroyCard(finalP1.getName(), westId);
                        addCard("west", westId);

                        try {
                            Thread.sleep(waitTime);
                            discard();
                            synchronized (o) {
                                o.notify();
                            }

                        } catch (InterruptedException ex) {
                            throw new RuntimeException(ex);
                        }
                    });

                    synchronized (o) {
                        o.wait();
                    }
                }
                //北 或 东
                else {

                    ImageView toNorth = (ImageView) getByName(p.getName()).lookup("#" + toPresentCard);

                    toNorth.setEffect(new DropShadow(15, Color.valueOf("#7174ff")));
                    Thread.sleep(waitTime);

                    String northId = toNorth.getId();

                    log.info("{} 得到 {}", startPlayer.getName(), northId);
                    toNorth.setEffect(null);

                    Object o = new Object();
                    Player finalP2 = p;
                    Player finalStartPlayer1 = startPlayer;
                    Platform.runLater(() -> {
                        destroyCard(finalP2.getName(), northId);
                        addCard(finalStartPlayer1.getName(), northId);

                        try {
                            Thread.sleep(waitTime);
                            discard();
                            synchronized (o) {
                                o.notify();
                            }
                        } catch (InterruptedException ex) {
                            throw new RuntimeException(ex);
                        }
                    });

                    synchronized (o) {
                        o.wait();
                    }
                }
            }

        }
    }

    private void end(Player startPlayer) {
        if (game.getPlayerList().stream().filter(e -> ObjectUtil.notEqual(e.getName(), startPlayer.getName())).allMatch(Player::getFinished)) {
            game.setIsStarted(false);

            thread = null;

            Platform.runLater(() -> {

                Dialog<Pair<String, String>> dialog = new Dialog<>();
                dialog.initStyle(StageStyle.UTILITY);
                dialog.getDialogPane().getButtonTypes().addAll(ButtonType.OK, ButtonType.CANCEL);

                DialogPane dialogPane = dialog.getDialogPane();

                Button btnCancel = (Button) dialogPane.lookupButton(ButtonType.CANCEL);
                btnCancel.setPrefWidth(40);
                btnCancel.setPrefHeight(20);
                btnCancel.setText("返回");
                btnCancel.setOnAction(e -> CommonService.jumpButtonEvent(confirm, "main"));

                Button applyBtn = (Button) dialogPane.lookupButton(ButtonType.OK);
                applyBtn.setPrefWidth(40);
                applyBtn.setPrefHeight(20);
                applyBtn.setText("重玩");
                applyBtn.setOnAction(e -> {
                    PokerGen.genNewCard();
                    showCard(PokerGen.distributeCard());
                    new Thread(() -> {
                        try {
                            startGame();
                        } catch (InterruptedException ex) {
                            ex.printStackTrace();
                        }
                    }).start();
                });

                Label label = new Label("玩家 " + startPlayer.getName() + "抽到王八");
                label.setPrefWidth(150);
                label.setPrefHeight(100);

                dialog.getDialogPane().setContent(label);
                dialog.showAndWait();
            });


        }
    }

    private void destroyCard(String name, String card) {
        switch (name) {
            case "north":
                game.getPlayerList().get(3).getCards().remove(card);
                north.getChildren().remove(north.lookup("#" + card));
                if (game.getPlayerList().get(3).getCards().isEmpty()) {
                    game.getPlayerList().get(3).setFinished(true);
                }
                break;
            case "east":
                game.getPlayerList().get(0).getCards().remove(card);
                east.getChildren().remove(east.lookup("#" + card));
                if (game.getPlayerList().get(0).getCards().isEmpty()) {
                    game.getPlayerList().get(0).setFinished(true);
                }
                break;
            case "west":
                game.getPlayerList().get(2).getCards().remove(card);
                west.getChildren().remove(west.lookup("#" + card));
                if (game.getPlayerList().get(2).getCards().isEmpty()) {
                    game.getPlayerList().get(2).setFinished(true);
                }
                break;
            case "south":
                game.getPlayerList().get(1).getCards().remove(card);
                south.getChildren().remove(south.lookup("#" + card));
                if (game.getPlayerList().get(1).getCards().isEmpty()) {
                    game.getPlayerList().get(1).setFinished(true);
                }
                break;
            default:
        }
    }

    private void addCard(String name, String card) {
        switch (name) {
            case "north":

                game.getPlayerList().get(3).getCards().add(card);
                Collections.shuffle(game.getPlayerList().get(3).getCards());
                north.getChildren().clear();
                for (String s : game.getPlayerList().get(3).getCards()) {
                    ImageView northCard = new ImageView();
                    northCard.setId(s);
                    northCard.setFitWidth(53);
                    northCard.setFitHeight(75);
                    northCard.setPreserveRatio(true);
                    northCard.setPickOnBounds(true);

                    northCard.setImage(new Image(CommonService.getPicUrl("/img/vertical.jpg")));
                    north.getChildren().add(northCard);
                }

                break;
            case "east":

                game.getPlayerList().get(0).getCards().add(card);
                Collections.shuffle(game.getPlayerList().get(0).getCards());
                east.getChildren().clear();
                for (String s : game.getPlayerList().get(0).getCards()) {
                    ImageView eastCard = new ImageView();
                    eastCard.setId(s);
                    eastCard.setFitWidth(75);
                    eastCard.setFitHeight(53);
                    eastCard.setPreserveRatio(true);
                    eastCard.setPickOnBounds(true);

                    eastCard.setImage(new Image(CommonService.getPicUrl("/img/horizontal.jpg")));
                    east.getChildren().add(eastCard);
                }

                break;
            case "west":

                game.getPlayerList().get(2).getCards().add(card);
                Collections.shuffle(game.getPlayerList().get(2).getCards());
                west.getChildren().clear();
                for (String s : game.getPlayerList().get(2).getCards()) {
                    ImageView westCard = new ImageView();
                    westCard.setId(s);
                    westCard.setFitWidth(75);
                    westCard.setFitHeight(53);
                    westCard.setPreserveRatio(true);
                    westCard.setPickOnBounds(true);

                    westCard.setImage(new Image(CommonService.getPicUrl("/img/horizontal.jpg")));
                    west.getChildren().add(westCard);
                }

                break;
            case "south":

                game.getPlayerList().get(1).getCards().add(card);
                Collections.shuffle(game.getPlayerList().get(1).getCards());
                south.getChildren().clear();
                for (String s : game.getPlayerList().get(1).getCards()) {
                    ImageView southCard = new ImageView();
                    southCard.setId(s);
                    southCard.setFitWidth(53);
                    southCard.setFitHeight(75);
                    southCard.setPreserveRatio(true);
                    southCard.setPickOnBounds(true);

                    southCard.setImage(new Image(CommonService.getPicUrl("/img/" + s + ".jpg")));
                    south.getChildren().add(southCard);
                }

                break;
            default:
        }
    }

    public void initButton() {
        confirm.setOnMouseClicked(e -> {

            Optional<Node> otherCard;
            String name;

            if (west.getChildren().size() != 0) {
                otherCard = west.getChildren().stream()
                        .filter(node -> node.getEffect() != null).findFirst();
                name = "west";

            } else if (north.getChildren().size() != 0) {
                otherCard = north.getChildren().stream()
                        .filter(node -> node.getEffect() != null).findFirst();
                name = "north";

            } else {
                otherCard = east.getChildren().stream()
                        .filter(node -> node.getEffect() != null).findFirst();
                name = "east";

            }

            if (otherCard.isPresent()) {

                ImageView toSouth = (ImageView) otherCard.get();

                String southId = toSouth.getId();

                Platform.runLater(() -> {
                    destroyCard(name, southId);
                    addCard("south", southId);
                    try {
                        Thread.sleep(waitTime);
                        discard();
                    } catch (InterruptedException ex) {
                        throw new RuntimeException(ex);
                    }

                    for (Node child : west.getChildren()) {
                        child.setOnMouseClicked(null);
                    }

                    LockSupport.unpark(thread);
                });

            }
            //没选择
            else {
                CommonService.errorDialog("未选择要从对方抽取的牌");
            }

        });
    }

    private void print() throws InterruptedException {

        Player eastPlayer = game.getPlayerList().get(0);
        StringBuilder sb = new StringBuilder("[");
        if (!eastPlayer.getFinished()) {
            log.info("east 实际卡牌：{}", eastPlayer.getCards());

            for (Node child : east.getChildren()) {
                sb.append(child.getId()).append(", ");
            }
            if (sb.length() > 2) {
                sb.delete(sb.length() - 2, sb.length());
            }
            log.info("east 拥有卡牌：{}", sb.append("]"));
            int counter = 0;
            while (east.getChildren().size() != eastPlayer.getCards().size()) {
                if (counter < 10) {
                    Thread.sleep(1000);
                    counter++;
                    continue;
                }
                throw new RuntimeException("error east");
            }
        }

        Player southPlayer = game.getPlayerList().get(1);
        sb = new StringBuilder("[");
        if (!southPlayer.getFinished()) {
            log.info("south 实际卡牌：{}", southPlayer.getCards());
            for (Node child : south.getChildren()) {
                sb.append(child.getId()).append(", ");
            }
            if (sb.length() > 2) {
                sb.delete(sb.length() - 2, sb.length());
            }
            log.info("south 拥有卡牌：{}", sb.append("]"));
            int counter = 0;
            while (south.getChildren().size() != southPlayer.getCards().size()) {
                if (counter < 10) {
                    Thread.sleep(1000);
                    counter++;
                    continue;
                }
                throw new RuntimeException("error south");
            }
        }


        Player westPlayer = game.getPlayerList().get(2);
        sb = new StringBuilder("[");
        if (!westPlayer.getFinished()) {
            log.info("west 实际卡牌：{}", westPlayer.getCards());

            for (Node child : west.getChildren()) {
                sb.append(child.getId()).append(", ");
            }
            if (sb.length() > 2) {
                sb.delete(sb.length() - 2, sb.length());
            }
            log.info("west 拥有卡牌：{}", sb.append("]"));
            int counter = 0;
            while (west.getChildren().size() != westPlayer.getCards().size()) {
                if (counter < 10) {
                    Thread.sleep(1000);
                    counter++;
                    continue;
                }
                throw new RuntimeException("error west");
            }
        }


        Player northPlayer = game.getPlayerList().get(3);
        sb = new StringBuilder("[");
        if (!northPlayer.getFinished()) {
            log.info("north 实际卡牌：{}", northPlayer.getCards());

            for (Node child : north.getChildren()) {
                sb.append(child.getId()).append(", ");
            }

            if (sb.length() > 2) {
                sb.delete(sb.length() - 2, sb.length());
            }
            log.info("north 拥有卡牌：{}", sb.append("]"));
            int counter = 0;
            while (north.getChildren().size() != northPlayer.getCards().size()) {
                if (counter < 10) {
                    Thread.sleep(1000);
                    counter++;
                    continue;
                }
                throw new RuntimeException("error north");
            }
        }

    }

    private FlowPane getByName(String name) {
        switch (name) {
            case "north":
                return north;
            case "south":
                return south;
            case "east":
                return east;
            case "west":
                return west;
            default:
                return null;
        }
    }

    void showCard(Map<String, List<String>> cards) {

        south.getChildren().clear();
        north.getChildren().clear();
        east.getChildren().clear();
        west.getChildren().clear();

        for (String s : cards.get("south")) {
            ImageView imageView = new ImageView();
            imageView.setId(s);
            imageView.setFitWidth(53);
            imageView.setFitHeight(75);
            imageView.setPreserveRatio(true);
            imageView.setPickOnBounds(true);

            imageView.setImage(new Image(CommonService.getPicUrl("/img/" + s + ".jpg")));
            south.getChildren().add(imageView);
        }

        for (String s : cards.get("north")) {
            ImageView imageView = new ImageView();
            imageView.setId(s);
            imageView.setFitWidth(53);
            imageView.setFitHeight(75);
            imageView.setPreserveRatio(true);
            imageView.setPickOnBounds(true);

            imageView.setImage(new Image(CommonService.getPicUrl("/img/vertical.jpg")));
            north.getChildren().add(imageView);
        }

        for (String s : cards.get("east")) {
            ImageView imageView = new ImageView();
            imageView.setId(s);
            imageView.setFitWidth(75);
            imageView.setFitHeight(53);
            imageView.setPreserveRatio(true);
            imageView.setPickOnBounds(true);

            imageView.setImage(new Image(CommonService.getPicUrl("/img/horizontal.jpg")));
            east.getChildren().add(imageView);
        }

        for (String s : cards.get("west")) {
            ImageView imageView = new ImageView();
            imageView.setId(s);
            imageView.setFitWidth(75);
            imageView.setFitHeight(53);
            imageView.setPreserveRatio(true);
            imageView.setPickOnBounds(true);

            imageView.setImage(new Image(CommonService.getPicUrl("/img/horizontal.jpg")));
            west.getChildren().add(imageView);
        }

        List<Player> playerList = new ArrayList<>(8);

        playerList.add(new Player("east", cards.get("east"), false, false));
        playerList.add(new Player("south", cards.get("south"), false, false));
        playerList.add(new Player("west", cards.get("west"), false, false));
        playerList.add(new Player("north", cards.get("north"), false, false));

        game = new Game(playerList, Boolean.TRUE);
    }

    private boolean isMatched(String card1, String card2) {
        String type1 = card1.substring(0, 1);
        String type2 = card2.substring(0, 1);
        String num1 = card1.substring(1);
        String num2 = card2.substring(1);
        boolean matchedType = ("♠".equals(type1) && "♣".equals(type2)) ||
                ("♣".equals(type1) && "♠".equals(type2)) ||
                ("♥".equals(type1) && "♦".equals(type2)) ||
                ("♦".equals(type1) && "♥".equals(type2));

        boolean matchedNum = num1.equals(num2);
        return matchedType && matchedNum;
    }

}
